﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

namespace CorporationWars
{
    [Serializable]
    public class Corporation : BaseObject
    {
        public static float SpaceSize { get { return 50; } }
        public static float Floor { get { return 0.01f; } }

        protected decimal _Funds { get; set; }
        public decimal Funds { get { return _Funds; } }
        public string Name { get; set; }

        public List<BaseNode> Nodes { get; set; }

        protected CoreNode myCore { get; set; }

        public long Shares { get; set; }
        
        protected decimal _sharePrice { get; set; }

        public List<decimal> ThisCycleSharePriceHistory { get; set; }
        public Dictionary<string, List<decimal>> SharePriceHistory { get; set; }

        public List<RealEstate> RealEstate { get; set; }

        public static int CorporationCount { get; set; }
        static int myCorpIdx { get; set; }

        public static bool RecordSharePrice { get; set; }

        public decimal SharePrice 
        {
            get
            {
                return _sharePrice;
            }
            set
            {
                if (value < 0)
                    value = 0;

                if (RecordSharePrice)
                {
                    if (ThisCycleSharePriceHistory == null)
                        ThisCycleSharePriceHistory = new List<decimal>();

                    ThisCycleSharePriceHistory.Add(value);
                }

                _sharePrice = value;
            }
        }        

        public decimal CurrentBuySharePrice { get { return ThisCycleSharePriceHistory[0]; } }

        public Vector3 Position { get; set; }

        public string LogoAsset { get; set; }

        public Color OuterColor = Color.Lime;

        public string Description { get; set; }

        public string SectorBase { get; set; }

        public float StaffMoral { get; set; }

        public string StockName { get; set; }

        public List<FinancialTransaction> FinancialTransactions { get; set; }

        public Dictionary<string, List<StockEntity>> StocksOwned { get; set; }

        public Dictionary<string, List<Staff>> Staff { get; set; }
        public List<Staff> AllStaff
        {
            get
            {
                List<Staff> allStf = new List<Staff>();

                foreach (string key in Staff.Keys)
                    allStf.AddRange(Staff[key]);

                return allStf;
            }
        }

        public decimal CycleSalary
        {
            get
            {
                decimal val = 0;
                List<Staff> allStf = AllStaff;

                foreach (Staff stf in allStf)
                    val += stf.Salary;

                val /= 12;

                return val;
            }
        }

        public Corporation(Game1 game) : base(game)
        {
            myCorpIdx = CorporationCount;
            CorporationCount++;
            
            Nodes = new List<BaseNode>();

            FinancialTransactions = new List<FinancialTransaction>();
            StocksOwned = new Dictionary<string, List<StockEntity>>();

            RealEstate = new List<RealEstate>();

            RecordSharePrice = true;
            SharePrice = (decimal)MathHelper.Lerp(.75f, 2, (float)Rnd.NextDouble());
            RecordSharePrice = false;
            
            StaffMoral = 1;

            LogoAsset = "Textures/Logo/baseLogo";


            Position = genNewPosition(SpaceSize);
        }

        public void AddStocks(StockEntity stocks)
        {
            if (!StocksOwned.ContainsKey(stocks.StockName))
                StocksOwned.Add(stocks.StockName, new List<StockEntity>());

            List<StockEntity> currentStock = StocksOwned[stocks.StockName];

            // Do we have a match
            int stockCnt = currentStock.Count;
            bool added = false;
            for (int stk = 0; stk < stockCnt; stk++)
            {
                if (currentStock[stk] == stocks)
                {
                    added = true;
                    currentStock[stk].Stocks += stocks.Stocks;
                    break;
                }
            }

            if (!added)
                currentStock.Add(stocks);

        }

        public void RemoveStock(StockEntity stocks)
        {
            List<StockEntity> currentStock = StocksOwned[stocks.StockName];

            // Stocks could have varying purchase prices..
            int stockCnt = currentStock.Count;
            bool removed = false;
            int stk;
            for (stk = 0; stk < stockCnt; stk++)
            {
                if (currentStock[stk] == stocks)
                {
                    currentStock[stk].Stocks -= stocks.Stocks;
                    if (currentStock[stk].Stocks <= 0)
                        removed = true;
                    break;
                }
            }

            if (removed)
                currentStock.RemoveAt(stk);

            if (currentStock.Count == 0)
                StocksOwned.Remove(stocks.StockName);
        }

        public void EndCycle(string lastCycleDate)
        {
            if (SharePriceHistory == null)
                SharePriceHistory = new Dictionary<string, List<decimal>>();

            SharePriceHistory.Add(lastCycleDate, new List<decimal>(ThisCycleSharePriceHistory));
            ThisCycleSharePriceHistory.Clear();
            ThisCycleSharePriceHistory.Add(SharePriceHistory[lastCycleDate][SharePriceHistory[lastCycleDate].Count - 1]);

            // Income
            MakeTransaction(new FinancialTransaction() { By = null, Value = CalcDividend(), Description = "Cycle Dividend" });

            // Outgoings
            MakeTransaction(new FinancialTransaction() { By = null, Value = -CycleSalary, Description = "Cycle Dividend" });
        }

        public void MakeTransaction(FinancialTransaction transaction)
        {
            _Funds += transaction.Value;
            FinancialTransactions.Add(transaction);
        }

        protected decimal CalcDividend()
        {
            if (StocksOwned.ContainsKey(StockName) && StocksOwned[StockName].Count > 0)
            {
                int MySharesOwned = StocksOwned[StockName].Sum(entity => entity.Stocks);
                return MySharesOwned * SharePrice;
            }
            else
                return 0;
        }
        protected decimal CalcBaseFunds()
        {
            return CalcDividend();
        }

        public Vector3 genNewPosition(float bounds, bool includeY = false, float mod = 2)
        {
            float x, y, z;

            x = (float)MathHelper.Lerp(-bounds, bounds, (float)Rnd.NextDouble());

            x = Game1.RoundToMultipleOf(x, mod);

            if(includeY)
                y = (float)MathHelper.Lerp(-bounds, bounds, (float)Rnd.NextDouble());
            else
                y = Floor;

            z = (float)MathHelper.Lerp(-bounds, bounds, (float)Rnd.NextDouble());

            

            return new Vector3(x, y, z);
        }

        
        public Corporation(Game1 game,string name, float sharePrice)
            : this(game, name)
        {
            RecordSharePrice = true;
            SharePrice -= SharePrice; // Counter stats..
            SharePrice = (decimal)sharePrice;
            RecordSharePrice = false;
            MakeTransaction(new FinancialTransaction() { By = null, Value = CalcBaseFunds(), Description = "Floatation on the market." });
        }

        public Corporation(Game1 game, string name, decimal funds)
            : this(game, name)
        {
            MakeTransaction(new FinancialTransaction() { By = null, Value = funds, Description = "Floatation on the market." });
        }

        protected void GenStockName(int attempt)
        {
            string[] elements = Name.Replace("&","").Replace(" of "," ").ToUpper().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            StockName = string.Empty;
            foreach (string s in elements)
                StockName += s[0].ToString();

            if (attempt != 0)
                StockName += string.Format("-{0}", attempt);
        }

        public Corporation(Game1 game, string name) : this(game)
        {
            Name = name;

            int att = 0;
            GenStockName(att++);
            // gen stock name
            while (!game.RegisterStockName(StockName))
                GenStockName(att++);

            game.RegisterCorp(this);

            Shares = 1000000;
            long MySharesOwned = Shares / 2;

            AddStocks(GetMyLatestStockEntity(string.Empty, (int)MySharesOwned));
            MakeTransaction(new FinancialTransaction() { By = this, Value = CalcBaseFunds(), Description = "Floatation on the market." });

            // Add minumum codes.
            myCore = new CoreNode(Game);
            AddNode(myCore, false);

            AddNode(new InfoTechNode(Game));

            AddNode(new FinancialNode(Game));
            Nodes[Nodes.Count - 1].ConnectTo(Nodes[Nodes.Count - 2], true);

            AddNode(new AdminNode(Game));
            Nodes[Nodes.Count - 1].ConnectTo(Nodes[Nodes.Count - 3], true);

            AddNode(new HRNode(Game));
            Nodes[Nodes.Count - 1].ConnectTo(Nodes[Nodes.Count - 2], true);
            Nodes[Nodes.Count - 1].ConnectTo(Nodes[Nodes.Count - 4], true);

        }

        public StockEntity GetMyLatestStockEntity(string dateRestriction, int stocks = 0)
        {
            return new StockEntity(StockName, stocks, CurrentBuySharePrice, dateRestriction);
        }

        public BaseNode getNode(string name)
        {
            return Nodes.SingleOrDefault(entity => entity.Name == name);
        }

        public void AddNode(BaseNode node, bool connectToCore = true)
        {
            node.CorperationID = this.ID;
            Nodes.Add(node);

            if (connectToCore)
                Nodes[Nodes.Count - 1].ConnectTo(myCore, false);

            if (Staff == null)
                Staff = new Dictionary<string, List<Staff>>();

            foreach (SalaryLevels salLvlv in Nodes[Nodes.Count - 1].PersonelRequired)
            {
                if (!Staff.ContainsKey(node.Name))
                    Staff.Add(node.Name, new List<Staff>());

                Staff[node.Name].Add(new Staff(node.Name, salLvlv));
            }
        }

        public void RemoveNode(BaseNode node)
        {
            Nodes.Remove(node);

            node.CloseNode();

            // Go through all other nodes and remove connections.
            foreach (BaseNode n in Nodes)
            {
                if (n.AmIConnectedTo(node))
                    n.RemoveConnection(node);
            }
        }

        public List<BaseNode> AllVisibleNodes
        {
            get { return new List<BaseNode>(Nodes.Where(entity => entity.IsVisibleFromOtherNodes)); }
        }

        public List<BaseNode> ExternallyVisibleNodes
        {
            get 
            { 
                return new List<BaseNode>(Nodes.Where(entity => (entity.IsVisibleFromOtherNodes && entity.HasExternalAccess) || myCorp).OrderByDescending(entity => entity.distanceFromCamera)); 
            }
        }

        public bool Inside = false;

        public Vector3 renderPos { get { return Position + new Vector3(0, height, 0); } }
        public Vector3 name3DPos { get { return Position + new Vector3(0, height*2, 0); } }
        public Matrix world { get { return (Matrix.CreateScale(new Vector3(1, height, 1)) * Matrix.CreateTranslation(renderPos)); } }
        public BoundingBox RenderedBounds { get { return new BoundingBox(-Vector3.One, Vector3.One); } }
        public BoundingBox Bounds { get { return new BoundingBox(Vector3.Transform(-Vector3.One, world), Vector3.Transform(Vector3.One, world)); } }
        public bool RenderBounds = false;

        //public FireWallData fwd;

        public float height { get { return (float)Funds / 1000000f; } }

        public void DrawCorpBoxName()
        {
            string nap = GetCorporateNameAndSharePriceAndToken();
            Vector2 namePos = Game1.Get2DCoords(name3DPos, Game.camera);
            Vector2 dims = Game.Content.Load<SpriteFont>("Fonts/Font").MeasureString(nap);
            namePos.X -= dims.X / 2;
            namePos.Y -= dims.Y * 2;

            Game.DrawBubble(new Rectangle((int)namePos.X - 10, (int)namePos.Y - 6, (int)dims.X + 16, (int)dims.Y + 16), Color.Black, new Vector2(0,1),16);
            Game.DrawBubble(new Rectangle((int)namePos.X - 8, (int)namePos.Y - 8, (int)dims.X + 16, (int)dims.Y + 16), Color.White, new Vector2(0, 1),16);
            Game.RenderText(nap, namePos, Color.Gold);
        }

        public string CorporateNameAndSharePriceAndToken
        {
            get { return string.Format("{0} - {1:0.00} [{2}]", Name, CurrentBuySharePrice, StockName); }
        }
        public string GetCorporateNameAndSharePriceAndToken()
        {
            return CorporateNameAndSharePriceAndToken;
        }
        
        [NonSerialized]
        GeomInstance myInstance;
        public void Draw(GameTime gameTime)
        {
            //if (myInstance == null)
            //{
            //    myInstance = new GeomInstance(Game);
            //    //myInstance.Bounds = Bounds;
            //    myInstance.Position = renderPos;
            //    myInstance.Scale = new Vector3(1, height, 1);
            //    myInstance.Rotation = Quaternion.Identity;

            //    myInstance.Instancer = Game.Sectors[SectorBase].CorpInstancer;
            //}

            //distFromCamera = Vector3.Distance(Position, Game.camera.Position);

            // Draw a block..
            //string tech = "OutsideRender";
            //if (Inside)
            //    tech = "InsideRender";

            //Game.DrawMesh(Game.Content.Load<Model>("Models/Block"), world, tech, OuterColor);

            //if (RenderBounds)
            //    DrawBounds(Game, Game.camera);

            //if (fwd != null)
            //    Game.DrawFireWall(fwd);
        }

        List<BaseNode> drawnNodes = new List<BaseNode>();
        float interiorSize = 0;
        bool myCorp = false;
        public void DrawExternalNodes(GameTime gameTime)
        {            
            // node distances
            foreach (BaseNode node in Nodes)
            {
                node.distanceFromCamera = Vector3.Distance(node.Position, Game.camera.Position);
            }

            List<BaseNode> nodes = ExternallyVisibleNodes;
            drawnNodes.Clear();
            interiorSize = Nodes.Count * 1.5f;

            myCorp = this == Game.playerCorp;
            
            // draw nodes
            if (selectedNode == null)
            {
                foreach (BaseNode node in nodes)
                {
                    node.IsMyCorp = myCorp;

                    if (!drawnNodes.Contains(node))
                    {
                        if (node.Position == Vector3.Zero)
                        {
                            node.Position = genNewPosition(interiorSize, true);

                            // Are we clear from others?
                            foreach (BaseNode nodeP in nodes)
                            {
                                if (nodeP != node)
                                    while (Vector3.Distance(node.Position, nodeP.Position) < 3f)
                                        node.Position = genNewPosition(interiorSize, true);
                            }
                        }

                        if (node.IsVisibleFromOtherNodes || myCorp)
                            DrawNode(node, Game, gameTime, Game.camera);
                    }
                }
            }

            SpriteBatch spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            // Render Corporation info;            
            Color color = Color.DeepSkyBlue;

            int leftMargin = 20;
            int tFloor = 130;

            if (myCorp)
                color = Color.Orange;

            if (selectedNode != null)
            {
                if (myCorp)
                    selectedNode.DrawDigitalCurtain(Game.ColorArray[Color.Green]);
                else
                    selectedNode.DrawDigitalCurtain(Game.ColorArray[Color.SteelBlue]);
            }

            spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/textBoxBG"), new Rectangle(8, 48, 400, 512), null, color, 0, Vector2.Zero, SpriteEffects.None, 1);
            spriteBatch.Draw(Game.Content.Load<Texture2D>(LogoAsset), new Rectangle(leftMargin, 64, 64, 64), null, Color.White, 0, Vector2.Zero, SpriteEffects.None, 1);

            Game.RenderText(Name, new Vector2(leftMargin + 70, 56 + Game.TextLineSpacing), color);

            tFloor += Game.RenderText(string.Format("Current Share Price: ${0:0.00}", CurrentBuySharePrice), new Vector2(leftMargin, tFloor), color);

            if(myCorp)
                tFloor += Game.RenderText(string.Format("Current Funds: ${0:#,###,###,##0.00}", Funds), new Vector2(leftMargin, tFloor), color);

            Game.RenderText("Description:-", new Vector2(leftMargin, tFloor + Game.TextLineSpacing), color);
            int lp = Game.RenderText(Description, new Vector2(leftMargin, tFloor + (2 * Game.TextLineSpacing)), color, 380);

            if (hoverNode != null && selectedNode == null)
            {
                color = Color.White;
                int ls = Game.Content.Load<SpriteFont>("Fonts/FontSmall").LineSpacing;
                tFloor += (2 * Game.TextLineSpacing) + lp;

                if (!myCorp)
                {
                    tFloor += Game.RenderText(string.Format("Pinging Node [{0}]...", hoverNode.Name), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    tFloor += Game.RenderText(string.Format("{0}", hoverNode.Description), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    tFloor += Game.RenderText("...", new Vector2(leftMargin, tFloor), color);

                    if (hoverNode.Software.Count > 0)
                        color = Color.OrangeRed;

                    // Show the top level software...
                    tFloor += Game.RenderText(string.Format("Visible Software Security [{0}]", hoverNode.Software.Count > 0 ? "Yes" : "No"), new Vector2(leftMargin, tFloor), color, -1, "Fonts/FontSmall");
                    if (hoverNode.Software.Count > 0)
                    {
                        color = Color.DarkOrange;
                        tFloor += Game.RenderText(string.Format("[{0} - {1}]", hoverNode.Software[0].ShortName, hoverNode.Software[0].Name), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    }
                }
                else
                {
                    tFloor += Game.RenderText(string.Format("Click to select [{0}]...", hoverNode.Name), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                }
            }

            if (selectedNode != null)
            {
                selectedNode.IsMyCorp = myCorp;
                color = Color.Lime;
                int ls = Game.Content.Load<SpriteFont>("Fonts/FontSmall").LineSpacing;
                tFloor += (2 * Game.TextLineSpacing) + lp;

                if (!myCorp)
                {
                    tFloor += Game.RenderText(string.Format("Attacking Node [{0}]...", selectedNode.Name), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    tFloor += Game.RenderText(string.Format("{0}", selectedNode.Description), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    tFloor += Game.RenderText("...", new Vector2(leftMargin, tFloor), color);

                    if (selectedNode.Software.Count > 0)
                        color = Color.OrangeRed;

                    // Show the top level software...
                    tFloor += Game.RenderText(string.Format("Visible Software Security [{0}]", selectedNode.Software.Count > 0 ? "Yes" : "No"), new Vector2(leftMargin, tFloor), color, -1, "Fonts/FontSmall");
                    if (selectedNode.Software.Count > 0)
                    {
                        color = Color.DarkOrange;
                        tFloor += Game.RenderText(string.Format("[{0} - {1}]", selectedNode.Software[0].ShortName, selectedNode.Software[0].Name), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    }
                }
                else
                {
                    tFloor += Game.RenderText(string.Format("[{0}]...", selectedNode.Name), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    // Employees in this node.
                    tFloor += Game.RenderText("Node Employees:-", new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    List<Staff> employees = Staff[selectedNode.Name];
                    foreach (Staff employee in employees)
                    {
                        tFloor += Game.RenderText(string.Format("{0} {1} ${2:0.00}",employee.Name.FullName,employee.SalaryBand, employee.Salary), new Vector2(leftMargin, tFloor), color, 380, "Fonts/FontSmall");
                    }
                }

                selectedNode.DrawNode(gameTime);
            }
        }

        public void DrawNode(BaseNode node, Game1 Game, GameTime gameTime, Camera camera)
        {
            DrawNodeBox(node, Game, gameTime, camera);

            // Draw software defences like fire walls :P
            Software hasFireWall = node.Software.SingleOrDefault(entity => entity.ShortName == "Firewall");
            if (hasFireWall != null)
            {
                if (hasFireWall.RenderData == null)
                    hasFireWall.RenderData = new FireWallData(string.Format("{0} - {1}", node.ShortName, hasFireWall.ShortName), node.Position - new Vector3(0, 1, 0), new Vector3(1.5f, 1.5f, 1), Color.White, hasFireWall.Attributes.Visibility);

                Game.DrawFireWall((FireWallData)hasFireWall.RenderData);
            }

            drawnNodes.Add(node);

            List<NodeConnection> connections = node.Connections;
            List<BaseNode> nodes = drawnNodes;

            // Draw the connections and nodes connected..
            foreach (NodeConnection connection in connections)
            {
                // Draw the connected node..
                if (!drawnNodes.Contains(connection.EndPoints[1].Node) && (myCorp || connection.EndPoints[1].Node.IsVisibleFromOtherNodes))
                {
                    // Are we clear from others?
                    if (connection.EndPoints[1].Node.Position == Vector3.Zero)
                    {
                        foreach (BaseNode nodeP in nodes)
                        {
                            if (nodeP != connection.EndPoints[1].Node)
                                while (connection.EndPoints[1].Node.Position == Vector3.Zero || Vector3.Distance(connection.EndPoints[1].Node.Position, nodeP.Position) < 3f)
                                    connection.EndPoints[1].Node.Position = genNewPosition(interiorSize, true);

                            if (connection.EndPoints[1].Node.Position != Vector3.Zero)
                                break;
                        }
                    }

                    if (connection.EndPoints[1].Node.IsVisibleFromOtherNodes || myCorp)
                        DrawNode(connection.EndPoints[1].Node, Game, gameTime, camera);
                }
                if(drawnNodes.Contains(connection.EndPoints[1].Node) && (myCorp || connection.EndPoints[1].Node.IsVisibleFromOtherNodes))
                {
                    // Draw connection..
                    Game.GraphicsDevice.DepthStencilState = DepthStencilState.None;
                    Game.GraphicsDevice.BlendState = BlendState.Opaque;
                    if (shader == null)
                        shader = new BasicEffect(Game.GraphicsDevice);

                    shader.World = Matrix.Identity;
                    shader.View = camera.View;
                    shader.Projection = camera.Projection;
                    shader.VertexColorEnabled = true;

                    shader.CurrentTechnique.Passes[0].Apply();

                    VertexPositionColor[] line = new VertexPositionColor[2];

                    Color col = Color.Red;

                    line[0] = new VertexPositionColor(node.Position, col);
                    line[1] = new VertexPositionColor(connection.EndPoints[1].Node.Position, col);
                    Game.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, line, 0, line.Length/2);

                    Game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;                    
                }
            }
            
        }

        public float distFromCamera = float.MaxValue;

        public void Update(GameTime gameTime)
        {
            #region Inside Corp
            if (Inside)
            {
                if (selectedNode != null)
                    selectedNode.UpdateNode(gameTime);

                if (Game.IsMouseOverUIZone == null)
                {
                    float nearestNode = float.MaxValue;
                    List<BaseNode> rayList = new List<BaseNode>();
                    List<BaseNode> rayHList = new List<BaseNode>();
                    foreach (BaseNode node in drawnNodes)
                    {
                        Matrix wrld = Matrix.CreateTranslation(node.Position);
                        BoundingBox bb = new BoundingBox(Vector3.Transform(-Vector3.One, wrld), Vector3.Transform(Vector3.One, wrld));

                        if (Game.IsMouseClickedOnBox(bb))
                            rayList.Add(node);

                        if (Game.IsMouseoverBox(bb))
                            rayHList.Add(node);
                    }
                    BaseNode sNode = null;
                    foreach (BaseNode node in rayList)
                    {
                        float d = Vector3.Distance(node.Position, Game.camera.Position);

                        if (d < nearestNode)
                        {
                            nearestNode = d;
                            if (sNode == node)
                                sNode = null;
                            else
                            {
                                sNode = node;
                                if (Game.AudioOn && Game.SFXOn)
                                    Game.Content.Load<SoundEffect>("Audio/SFX/select").Play(.1f, 0, 0);
                            }
                        }
                    }

                    if (sNode != null)
                        SetSelectedNode(sNode);

                    nearestNode = float.MaxValue;
                    BaseNode hNode = null;
                    foreach (BaseNode node in rayHList)
                    {
                        float d = Vector3.Distance(node.Position, Game.camera.Position);

                        if (d < nearestNode)
                        {
                            nearestNode = d;

                            hNode = node;
                        }
                    }

                    if (hNode != null)
                    {
                        if (hoverNode != hNode && hNode != selectedNode && Game.AudioOn && Game.SFXOn)
                            Game.Content.Load<SoundEffect>("Audio/SFX/nodeHover").Play(.025f, 0, 0);

                        hoverNode = hNode;
                    }
                    else
                        hoverNode = null;
                }
            }
            #endregion
            else
            {
                if (myInstance == null)
                    myInstance = new GeomInstance(Game, renderPos, new Vector3(1, height, 1), Quaternion.Identity, ref Game.Sectors[SectorBase].CorpInstancer);

                distFromCamera = Vector3.Distance(Position, Game.camera.Position);
                myInstance.Position = renderPos;
                myInstance.Scale = new Vector3(1, height, 1);
                myInstance.Rotation = Quaternion.Identity;
                myInstance.DistanceFromCamera = distFromCamera;
                myInstance.InstanceColor = OuterColor;
                myInstance.Update(gameTime);
            }
        }

        BaseNode selectedNode = null;
        BaseNode hoverNode = null;

        public void EnterCorp()
        {
            Inside = true;
        }

        public void ExitCorp()
        {
            // Reset visuals..
            Inside = false;
            UnSetSelectedNode();
        }

        public void SetSelectedNode(BaseNode node)
        {
            if (selectedNode != null && selectedNode != node)
                selectedNode.ExitNode();

            selectedNode = node;
            selectedNode.OnExit = ExitNodeEvent;
        }

        void ButtonClicked(UIButton sender)
        {
            switch (sender.Name)
            {
                default:
                    break;
            }
        }

        protected void ExitNodeEvent(BaseNode node)
        {
            if (node == selectedNode)
                selectedNode = null;
        }
        public void UnSetSelectedNode()
        {
            if(selectedNode != null)
                selectedNode.ExitNode();
        }

        public void SetSelectedNode(string name)
        {
            SetSelectedNode(getNode(name));
        }

        public void DrawNodeBox(BaseNode node, Game1 Game, GameTime gameTime, Camera camera)
        {
            //Game.GraphicsDevice.DepthStencilState = DepthStencilState.None;
            Game.GraphicsDevice.BlendState = BlendState.Opaque;

            Matrix wrld = Matrix.CreateTranslation(node.Position);
            BoundingBox bb = new BoundingBox(Vector3.Transform(-Vector3.One, wrld), Vector3.Transform(Vector3.One, wrld));

            Color color = Color.DeepSkyBlue;

            bool mouseOver = hoverNode == node;
            
            if (myCorp)
                color = Color.Orange;

            if (mouseOver)
                color = Color.White;
            
            if (selectedNode != null && selectedNode == node)
                color = Color.LimeGreen;
            
            Game.DrawMesh(Game.Content.Load<Model>("Models/Block"),wrld, "OutsideRender", color);

            Vector2 namePos = Game1.Get2DCoords(node.Position, camera);
            namePos.X -= Game.Content.Load<SpriteFont>("Fonts/Font").MeasureString(node.ShortName).X / 2;

            SpriteBatch spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));


            color = Color.Blue;
            if (myCorp)
                color = Color.Gold;

            if (mouseOver)
                color = Color.DarkGray;

            if (selectedNode != null && selectedNode == node)
                color = Color.Green;

            spriteBatch.DrawString(Game.Content.Load<SpriteFont>("Fonts/Font"), node.ShortName, namePos - new Vector2(1,-1), Color.Black);
            spriteBatch.DrawString(Game.Content.Load<SpriteFont>("Fonts/Font"), node.ShortName, namePos, color);
        }

        [NonSerialized]
        BasicEffect shader;
        protected VertexPositionColor[] points;
        protected short[] index;
        protected short[] indsMap = new short[] {
			    0, 1, 0, 
                2, 1, 3, 
                2, 3, 4, 
                5, 4, 6, 
                5, 7, 6, 
                7, 0, 4, 
                1, 5, 2, 
                6, 3, 7
		        };

        private void DrawBounds(Game Game, Camera camera)
        {
            
            BuildBoxCorners();

            if (shader == null)
                shader = new BasicEffect(Game.GraphicsDevice);            

            shader.World = Matrix.Identity;
            shader.View = camera.View;
            shader.Projection = camera.Projection;
            shader.VertexColorEnabled = true;

            shader.CurrentTechnique.Passes[0].Apply();
            Game.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.LineList, points, 0, points.Length, index, 0, 12);
        }
        protected void BuildBoxCorners()
        {

            points = new VertexPositionColor[8];
            short[] inds = new short[points.Length * 3];

            Vector3[] thisCorners = RenderedBounds.GetCorners();

            for (int c = 0; c < thisCorners.Length; c++)
            {
                thisCorners[c] = Vector3.Transform(thisCorners[c], world);
            }

            points[0] = new VertexPositionColor(thisCorners[1], Color.Red);
            points[1] = new VertexPositionColor(thisCorners[0], Color.Red);
            points[2] = new VertexPositionColor(thisCorners[2], Color.Red);
            points[3] = new VertexPositionColor(thisCorners[3], Color.Red);
            points[4] = new VertexPositionColor(thisCorners[5], Color.Red);
            points[5] = new VertexPositionColor(thisCorners[4], Color.Red);
            points[6] = new VertexPositionColor(thisCorners[6], Color.Red);
            points[7] = new VertexPositionColor(thisCorners[7], Color.Red);

            for (int i = 0; i < 24; i++)
            {
                inds[i] = (short)(indsMap[i]);
            }
            

            index = inds;
        }

        public void ReWire(Game1 game)
        {
            Game = game;
            foreach (BaseNode node in Nodes)
                node.ReWire(Game);
        }

        public void UnWire()
        {
            foreach (BaseNode node in Nodes)
                node.UnWire();
        }
    }
}
